package com.caption.service;

import com.caption.convert.ProductConvert;
import com.caption.es.dao.ProductESDao;
import com.caption.es.dto.ProductES;
import com.caption.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;


@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductESDao productESDao;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 保存es对象
     */
    @Override
    public void save() {
        ProductES productES = new ProductES(100L, "华为Meta50", "手机", 8000.00, "http://localhost/555");
        productESDao.save(productES);
    }

    /**
     * 修改es对象
     */
    @Override
    public void update() {
        ProductES productES = new ProductES(100L, "华为Meta50", "手机", 6000.00, "http://localhost/555");
        productESDao.save(productES);
    }

    /**
     * 根据id查询
     */
    @Override
    public void findById() {
        Optional<ProductES> optional = productESDao.findById(100L);
        if (optional.isPresent()) {
            ProductES productES = optional.get();
            log.info("es根据id查询={}", productES);
        }
    }

    /**
     * 查询所有
     */
    @Override
    public void findAll() {
        Iterable<ProductES> productESList = productESDao.findAll();
        for (ProductES productES : productESList) {
            log.info("es获取所有对象={}", productES);
        }
    }

    /**
     * 批量保存
     */
    @Override
    public void saveList() {
        List<ProductES> productESList = new ArrayList<>();
        List<String> tag = Arrays.asList("国产", "低端");
        List<String> tag2 = Arrays.asList("国产", "高端");
        List<String> tag3 = Arrays.asList("外国", "高端");
        ProductES productES1 = new ProductES((100L), "小米8", "手机", 3000.00, "http://localhost:8081/1.png");
        productES1.setDesc("民族品牌屌爆了");
        productES1.setTags(tag);
        ProductES productES2 = new ProductES((101L), "Iphone12", "手机", 10800.00, "http://localhost:8081/2.png");
        productES2.setDesc("美国技术就是牛逼");
        productES2.setTags(tag3);
        ProductES productES3 = new ProductES((102L), "华为Meta50", "手机", 8880.00, "http://localhost:8081/2.png");
        productES3.setDesc("民族品牌，支持国产");
        productES3.setTags(tag2);
        ProductES productES4 = new ProductES((103L), "华为Meta40", "手机", 6880.00, "http://localhost:8081/2.png");
        productES4.setDesc("民族品牌，硬钢苹果");
        productES4.setTags(tag2);
        ProductES productES5 = new ProductES((104L), "奔驰500", "汽车", 596880.00, "http://localhost:8081/2.png");
        ProductES productES6 = new ProductES((105L), "宝马x6", "汽车", 896880.00, "http://localhost:8081/2.png");
        ProductES productES7 = new ProductES((106L), "比亚迪", "汽车", 896880.00, "http://localhost:8081/2.png");
        productES7.setDesc("国产汽车站起来了");
        productES7.setTags(tag2);
        productES5.setTags(tag3);
        productES6.setTags(tag3);
        productESList.add(productES1);
        productESList.add(productES2);
        productESList.add(productES3);
        productESList.add(productES4);
        productESList.add(productES5);
        productESList.add(productES6);
        productESList.add(productES7);
        productESDao.saveAll(productESList);
        log.info("批量插入成功");
    }

    @Override
    public void findPages() {
        //按照id倒叙排列
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        //从哪里开始
        int from = 0;
        //查询5条数据
        int pageSize = 5;
        PageRequest pageRequest = PageRequest.of(from, pageSize, sort);
        Page<ProductES> pageList = productESDao.findAll(pageRequest);
        for (ProductES productES : pageList.getContent()) {
            log.info("es分页查询={}", productES);
        }
    }

    @Override
    public void search() {
        //查询条件
        ProductES param = new ProductES();
        List<String> paramTag = Arrays.asList("国产");
        //param.setCategory("手机");
        param.setTags(paramTag);
        param.setDesc("民族");
        //构造查询条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        //should 相当于sql中  where 1=1   or category = '手机' or desc like '%民族%'
        if (StringUtils.isNotBlank(param.getCategory())) {
            queryBuilder.should(QueryBuilders.termQuery("category", param.getCategory()));
        }
        if (StringUtils.isNotBlank(param.getDesc())) {
            queryBuilder.should(QueryBuilders.termQuery("desc", param.getDesc()));
        }

        //must 相当于sql where tags in ('国产')
        if (!CollectionUtils.isEmpty(param.getTags())) {
            List<String> tags = param.getTags();
            for (String tag : tags) {
                queryBuilder.must(QueryBuilders.termQuery("tags", tag));
            }
        }
        //分页
        PageRequest pageRequest = PageRequest.of(0, 10);
        //高亮字段
        HighlightBuilder highlightBuilder = getHighlightBuilder(Arrays.asList("desc", "tags", "title"));
        //排序
        FieldSortBuilder sortBuilder = SortBuilders.fieldSort("id").order(SortOrder.DESC);
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .withPageable(pageRequest)
                .withSort(sortBuilder).build();
        List<SearchHit<ProductES>> searchHits = elasticsearchRestTemplate.search(searchQuery, ProductES.class).getSearchHits();
        List<ProductVo> dataList = new ArrayList<>();
        for (SearchHit<ProductES> searchHit : searchHits) {
            ProductES productES = searchHit.getContent();
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            ProductVo productVo = ProductConvert.INSTANCE.dto2vo(productES);
            //设置高亮字段
            for (String highlightField : highlightFields.keySet()) {
                if (StringUtils.equals(highlightField, "tags")) {
                    productVo.setTags(highlightFields.get(highlightField));
                } else if (StringUtils.equals(highlightField, "desc")) {
                    productVo.setDesc(highlightFields.get(highlightField).get(0));
                }
            }

            dataList.add(productVo);
        }
        log.info("匹配结果{}", dataList);
    }

    /**
     * 设置高亮字段
     * @param fields
     * @return
     */
    private HighlightBuilder getHighlightBuilder(List<String> fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }


}
